#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
#include <cassert>
#include <iomanip>
using namespace std;

#define THREAD_NUM 2
int tickets = 10000;

class ThreadData
{
public:
    ThreadData(const std::string &n, pthread_mutex_t *pm) : tname(n), pmutex(pm)
    {}
    std::string tname;
    pthread_mutex_t *pmutex;
};

void *getTickets(void *args)
{
    ThreadData *td = (ThreadData *)args;
    while (true)
    {
        // 抢占逻辑
        int n = pthread_mutex_lock(td->pmutex);
        assert(n == 0);
        // 临界区
        if (tickets > 0)
        { // 判断的本质也是计算的一种
            usleep(rand() % 1500);
            printf("%s: %d\n", td->tname.c_str(), tickets);
            tickets--;
            n = pthread_mutex_unlock(td->pmutex); // 也可能出现问题
            assert(n == 0);
        }
        else
        {
            n = pthread_mutex_unlock(td->pmutex);
            assert(n == 0);
            break;
        }
        // 抢完票，还需要后续的动作
        usleep(rand() % 2000);
    }
    delete td;
    return nullptr;
}

int main()
{
    time_t start = time(nullptr);
    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx, nullptr);

    srand((unsigned long)time(nullptr) ^ getpid() ^ 0x147);
    pthread_t t[THREAD_NUM];

    // 多线程抢票的逻辑
    for (int i = 0; i < THREAD_NUM; i++)
    {
        std::string name = "thread ";
        name += std::to_string(i + 1);
        ThreadData *td = new ThreadData(name, &mtx);
        pthread_create(t + i, nullptr, getTickets, (void *)td);
    }

    for (int i = 0; i < THREAD_NUM; i++)
    {
        pthread_join(t[i], nullptr);
    }
    pthread_mutex_destroy(&mtx);
    time_t end = time(nullptr);

    double elapsed_seconds = difftime(end, start);
    cout << fixed << setprecision(2) << "time:" << elapsed_seconds << "s" << endl;
}

